package com.geekhalo.demo.thread.paralleltask.fix;

import com.geekhalo.demo.thread.paralleltask.*;
import com.geekhalo.lego.core.web.RestResult;
import com.google.common.base.Stopwatch;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.concurrent.*;

@RequestMapping("threads/paralleltask/fix")
@RestController
@Slf4j
public class OrderDetailFixController {
    @Autowired
    private OrderService orderService;

    @Autowired
    private CouponService couponService;

    @Autowired
    private AddressService addressService;

    @Autowired
    private ProductService  productService;

    @Autowired
    private UserService userService;

    private ExecutorService executorService;

    @PostConstruct
    public void init(){
        int coreSize = Runtime.getRuntime().availableProcessors();
        executorService = new ThreadPoolExecutor(coreSize, coreSize * 5,
                5L, TimeUnit.MINUTES,
                new SynchronousQueue<>(),
                new ThreadPoolExecutor.CallerRunsPolicy()
                );
    }

    @GetMapping("detail/{orderId}")
    public RestResult<OrderDetailVO> getOrderDetailNew(@PathVariable Long orderId){
        Stopwatch stopwatch = Stopwatch.createStarted();
        OrderService.Order order = this.orderService.getById(orderId);
        if (order == null){
            return RestResult.success(null);
        }
        Future<UserService.User> userFuture = this.executorService.submit(() -> userService.getById(order.getUserId()));
        Future<AddressService.Address> addressFuture = this.executorService.submit(() -> addressService.getById(order.getUserAddressId()));
        Future<CouponService.Coupon> couponFuture = this.executorService.submit(() -> couponService.getById(order.getCouponId()));
//        Future<ProductService.Product> productFuture = this.executorService.submit(() -> productService.getById(order.getProductId()));

        OrderDetailVO orderDetail = new OrderDetailVO();
        // 由主线程负责运行
        orderDetail.setProduct(productService.getById(order.getProductId()));

        orderDetail.setUser(getFutureValue(userFuture));
        orderDetail.setAddress(getFutureValue(addressFuture));
        orderDetail.setCoupon(getFutureValue(couponFuture));
        log.info("并行 Cost {} ms", stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));
        return RestResult.success(orderDetail);
    }

    private <T> T getFutureValue(Future<T> future){
        try {
            return future.get();
        }catch (Exception e){

        }
        return null;
    }
}
